package com.ly.system.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ly.common.constant.UserConstants;
import com.ly.common.core.domain.AjaxResult;
import com.ly.common.core.domain.TreeSelect;
import com.ly.common.core.domain.entity.SysMenu;
import com.ly.common.core.domain.entity.SysRole;
import com.ly.common.core.domain.entity.SysUser;
import com.ly.common.exception.CustomException;
import com.ly.common.utils.DateUtils;
import com.ly.common.utils.SecurityUtils;
import com.ly.common.utils.StringUtils;
import com.ly.common.utils.erp.SnowflakeIdWorker;
import com.ly.system.domain.vo.MetaVo;
import com.ly.system.domain.vo.RouterVo;
import com.ly.system.mapper.SysMenuMapper;
import com.ly.system.mapper.SysRoleMapper;
import com.ly.system.mapper.SysRoleMenuMapper;
import com.ly.system.service.ISysMenuService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 菜单 业务层处理
 *
 * @author
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

    public static final String PREMISSION_STRING = "perms[\"{0}\"]";

    @Resource
    private SysMenuMapper sysMenuMapper;

    @Resource
    private SysRoleMapper sysRoleMapper;

    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;

    /**
     * 根据用户查询系统菜单列表
     *
     * @param userId 用户ID
     * @return 菜单列表
     */
    @Override
    public List<SysMenu> selectMenuList ( String userId ) {
        return selectMenuList ( new SysMenu (), userId );
    }

    /**
     * 查询系统菜单列表
     *
     * @param menu 菜单信息
     * @return 菜单列表
     */
    @Override
    public List<SysMenu> selectMenuList ( SysMenu menu, String userId ) {
        List<SysMenu> menuList = null;
        // 管理员显示所有菜单信息
        if ( SysUser.isAdmin ( userId ) ) {
            menuList = sysMenuMapper.selectMenuList ( menu );
        } else {
            menu.getParams ().put ( "userId", userId );
            menuList = sysMenuMapper.selectMenuListByUserId ( menu );
        }
        return menuList;
    }

    /**
     * 根据参数menuType和parentId获取对应的菜单和按钮列表
     */
    @Override
    public List<SysMenu> getMenuList ( SysMenu menu ) {
        List<SysMenu> sysMenus = sysMenuMapper.selectMenuList ( menu );
        return sysMenus;
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限列表
     */
    @Override
    public Set<String> selectMenuPermsByUserId ( String userId ) {
        List<String> perms = sysMenuMapper.selectMenuPermsByUserId ( userId );
        Set<String> permsSet = new HashSet<> ();
        for ( String perm : perms ) {
            if ( StringUtils.isNotEmpty ( perm ) ) {
                permsSet.addAll ( Arrays.asList ( perm.trim ().split ( "," ) ) );
            }
        }
        return permsSet;
    }

    /**
     * 根据用户ID查询菜单
     *
     * @param userId 用户名称
     * @return 菜单列表
     */
    @Override
    public JSONObject selectMenuTreeByUserId ( String userId ) {
        List<SysMenu> menus;
        if ( SecurityUtils.isAdmin ( userId ) ) {
            menus = sysMenuMapper.selectMenuTreeAll ();
        } else {
            menus = sysMenuMapper.selectMenuTreeByUserId ( userId );
        }
        List<SysMenu> childPerms = getChildPerms ( menus, "0" );
        List<SysMenu> childPermsCopy = deepCopyMenuList ( childPerms );
        List<SysMenu> filteredMenus = filterMenus ( childPermsCopy );
        JSONObject jsonObject = new JSONObject ();
        jsonObject.put ( "childPerms", filteredMenus ); // Use filtered menus
        jsonObject.put ( "noFilterChild", childPerms ); // Use unfiltered menus
        return jsonObject;
    }

    /**
     * 根据登录用户以及点击左侧一级目录，查询二级菜单到新页面
     *
     * @param userId
     * @return
     * @author Wuzh
     */
    @Override
    public JSONObject queryRoutersByUserId ( String userId, String parentId ) {
        List<SysMenu> menus;
        if ( SecurityUtils.isAdmin ( userId ) ) {
            menus = sysMenuMapper.queryRoutersTreeAll ( parentId );
        } else {
            Map<String, String> map = new HashMap<> ();
            map.put ( "userId", userId );
            map.put ( "parentId", parentId );
            menus = sysMenuMapper.queryMenuTreeByUserId ( map );
        }
        List<SysMenu> childPermsCopy = deepCopyMenuList ( menus );
        List<SysMenu> filteredMenus = filterMenus ( childPermsCopy );
        JSONObject jsonObject = new JSONObject ();
        jsonObject.put ( "childPerms", filteredMenus ); // Use filtered menus
        jsonObject.put ( "noFilterChild", menus ); // Use unfiltered menus
        return jsonObject;
    }

    /**
     * 深度复制菜单列表
     *
     * @param originalList
     * @return
     */
    private List<SysMenu> deepCopyMenuList ( List<SysMenu> originalList ) {
        List<SysMenu> copyList = new ArrayList<> ();
        for ( SysMenu menu : originalList ) {
            SysMenu copiedMenu = new SysMenu ( menu ); // Assuming SysMenu has a copy constructor
            if ( menu.getChildren () != null ) {
                copiedMenu.setChildren ( deepCopyMenuList ( menu.getChildren () ) );
            }
            copyList.add ( copiedMenu );
        }
        return copyList;
    }

    /**
     * 根据父节点的ID获取所有子节点
     *
     * @param list
     * @param parentId
     * @return
     */
//    public List<SysMenu> getChildPerms(List<SysMenu> allMenus, String parentId) {
//        return allMenus.stream()
//                .filter(menu -> menu.getParentId().equals(parentId))
//                .map(menu -> {
//                    menu.setChildren(getChildPerms(allMenus, menu.getMenuId()));
//                    return menu;
//                })
//                .collect(Collectors.toList());
//    }
    public List<SysMenu> getChildPerms ( List<SysMenu> list, String parentId ) {
        List<SysMenu> returnList = new ArrayList<SysMenu> ();
        for ( Iterator<SysMenu> iterator = list.iterator (); iterator.hasNext (); ) {
            SysMenu t = ( SysMenu ) iterator.next ();
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点l
            if ( t.getParentId ().equals ( parentId ) ) {
                recursionFn ( list, t );
                returnList.add ( t );
            }
        }
        return returnList;
    }

    /**
     * 递归列表
     *
     * @param list
     * @param t
     */
    private void recursionFn ( List<SysMenu> list, SysMenu t ) {
        // 得到子节点列表
        List<SysMenu> childList = getChildList ( list, t );
        t.setChildren ( childList );
        for ( SysMenu tChild : childList ) {
            if ( hasChild ( list, tChild ) ) {
                recursionFn ( list, tChild );
            }
        }
    }


    /**
     * 判断是否有子节点
     */
    private boolean hasChild ( List<SysMenu> list, SysMenu t ) {
        return getChildList ( list, t ).size () > 0 ? true : false;
    }

    /**
     * 判断是否有子节点
     *
     * @param list
     * @param parent
     * @return
     */
//    private boolean hasChild(List<SysMenu> list, SysMenu parent) {
//        return !getChildList(list, parent).isEmpty();
//    }

//    private List<SysMenu> getChildList(List<SysMenu> list, SysMenu parent) {
//        List<SysMenu> children = new ArrayList<>();
//        for (SysMenu menu : list) {
//            if (menu.getParentId().equals(parent.getMenuId())) {
//                children.add(menu);
//            }
//        }
//        return children;
//    }

    /**
     * 得到子节点列表
     */
    private List<SysMenu> getChildList ( List<SysMenu> list, SysMenu t ) {
        List<SysMenu> tlist = new ArrayList<SysMenu> ();
        Iterator<SysMenu> it = list.iterator ();
        while ( it.hasNext () ) {
            SysMenu n = ( SysMenu ) it.next ();
            if ( n.getParentId ().equals ( t.getMenuId () ) ) {
                tlist.add ( n );
            }
        }
        return tlist;
    }

    /**
     * 调整 filterMenus 方法，确保递归过滤子菜单
     *
     * @param menus
     * @return
     */
    public List<SysMenu> filterMenus ( List<SysMenu> menus ) {
        return menus.stream ().filter ( menu -> "1".equals ( menu.getHideRoute () ) ).map ( menu -> {
            menu.setChildren ( filterChildNodes ( menu.getChildren (), "1" ) );
            return menu;
        } ).collect ( Collectors.toList () );
    }

    public List<SysMenu> filterChildNodes ( List<SysMenu> menus, String hideRouteCondition ) {
        return menus.stream ().filter ( menu -> hideRouteCondition.equals ( menu.getHideRoute () ) ).map ( menu -> {
            menu.setChildren ( filterChildNodes ( menu.getChildren (), hideRouteCondition ) );
            return menu;
        } ).collect ( Collectors.toList () );
    }


    /**
     * 根据角色ID查询菜单树信息
     *
     * @param roleId 角色ID
     * @return 选中菜单列表
     */
    @Override
    public List<Integer> selectMenuListByRoleId ( String roleId ) {
        SysRole role = sysRoleMapper.selectRoleById ( roleId );
        return sysMenuMapper.selectMenuListByRoleId ( roleId, role.isMenuCheckStrictly () );
    }

    /**
     * 构建前端路由所需要的菜单
     *
     * @param menus 菜单列表
     * @return 路由列表
     */
    @Override
    public List<RouterVo> buildMenus ( List<SysMenu> menus ) {
        List<RouterVo> routers = new LinkedList<RouterVo> ();
        for ( SysMenu menu : menus ) {
            RouterVo router = new RouterVo ();
            router.setMenuId ( menu.getMenuId () );
            router.setIsMenuBtn ( menu.getIsMenuBtn () );
            router.setLevel ( menu.getLevel () );
            router.setHidden ( "1".equals ( menu.getVisible () ) );
            router.setName ( getRouteName ( menu ) );
            router.setPath ( getRouterPath ( menu ) );
            router.setComponent ( getComponent ( menu ) );
            router.setMeta ( new MetaVo ( menu.getMenuName (), menu.getIcon (), StringUtils.equals ( "1", menu.getIsCache () ) ) );
            List<SysMenu> cMenus = menu.getChildren ();
            if ( ! cMenus.isEmpty () && cMenus.size () > 0 && UserConstants.TYPE_DIR.equals ( menu.getMenuType () ) ) {
                router.setAlwaysShow ( true );
                router.setRedirect ( "noRedirect" );
                router.setChildren ( buildMenus ( cMenus ) );
            } else if ( isMeunFrame ( menu ) ) {
                List<RouterVo> childrenList = new ArrayList<RouterVo> ();
                RouterVo children = new RouterVo ();
                children.setMenuId ( menu.getMenuId () );
                children.setPath ( menu.getPath () );
                children.setComponent ( menu.getComponent () );
                children.setName ( StringUtils.capitalize ( menu.getPath () ) );
                children.setMeta ( new MetaVo ( menu.getMenuName (), menu.getIcon (), StringUtils.equals ( "1", menu.getIsCache () ) ) );
                childrenList.add ( children );
                router.setChildren ( childrenList );
            }
            routers.add ( router );
        }
        return routers;
    }

    /**
     * 构建前端所需要树结构
     *
     * @param menus 菜单列表
     * @return 树结构列表
     */
    @Override
    public List<SysMenu> buildMenuTree ( List<SysMenu> menus ) {
        List<SysMenu> returnList = new ArrayList<SysMenu> ();
        List<String> tempList = new ArrayList<> ();
        for ( SysMenu dept : menus ) {
            tempList.add ( dept.getMenuId () );
        }
        for ( Iterator<SysMenu> iterator = menus.iterator (); iterator.hasNext (); ) {
            SysMenu menu = ( SysMenu ) iterator.next ();
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if ( ! tempList.contains ( menu.getParentId () ) ) {
                recursionFn ( menus, menu );
                returnList.add ( menu );
            }
        }
        if ( returnList.isEmpty () ) {
            returnList = menus;
        }
        return returnList;
    }

    /**
     * 构建前端所需要下拉树结构
     *
     * @param menus 菜单列表
     * @return 下拉树结构列表
     */
    @Override
    public List<TreeSelect> buildMenuTreeSelect ( List<SysMenu> menus ) {
        List<SysMenu> menuTrees = buildMenuTree ( menus );
        return menuTrees.stream ().map ( TreeSelect :: new ).collect ( Collectors.toList () );
    }

    /**
     * 根据菜单ID查询信息
     *
     * @param menuId 菜单ID
     * @return 菜单信息
     */
    @Override
    public SysMenu selectMenuById ( String menuId ) {
        return sysMenuMapper.selectMenuById ( menuId );
    }

    /**
     * 是否存在菜单子节点
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    @Override
    public boolean hasChildByMenuId ( String menuId ) {
        int result = sysMenuMapper.hasChildByMenuId ( menuId );
        return result > 0 ? true : false;
    }

    /**
     * 查询菜单使用数量
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    @Override
    public boolean checkMenuExistRole ( String menuId ) {
        int result = sysRoleMenuMapper.checkMenuExistRole ( menuId );
        return result > 0 ? true : false;
    }

    /**
     * 新增保存菜单信息
     *
     * @param menu 菜单信息
     * @return 结果
     */
    @Override
    public AjaxResult insertMenu ( SysMenu menu ) {
        menu.setMenuId ( SnowflakeIdWorker.getInstance ().nextStringId () );
        menu.setCreateTime ( DateUtils.getNowDate () );
        menu.setLevel ( menu.getLevel () == null ? 0 : ( menu.getLevel () - 1 ) );
        boolean save = this.save ( menu );
        if ( ! save ) {
            throw new CustomException ( "新增菜单失败！" );
        }
        return AjaxResult.success ();
    }

    /**
     * 修改保存菜单信息
     *
     * @param menu 菜单信息
     * @return 结果
     */
    @Override
    public int updateMenu ( SysMenu menu ) {
        return sysMenuMapper.updateMenu ( menu );
    }

    /**
     * 删除菜单管理信息
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    @Override
    public int deleteMenuById ( String menuId ) {
        return sysMenuMapper.deleteMenuById ( menuId );
    }

    /**
     * 校验菜单名称是否唯一
     *
     * @param menu 菜单信息
     * @return 结果
     */
    @Override
    public String checkMenuNameUnique ( SysMenu menu ) {
        String menuId = StringUtils.isNull ( menu.getMenuId () ) ? "-1" : menu.getMenuId ();
        SysMenu info = sysMenuMapper.checkMenuNameUnique ( menu.getMenuName (), menu.getParentId () );
        if ( StringUtils.isNotNull ( info ) && ! info.getMenuId ().equals ( menuId ) ) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 获取路由名称
     *
     * @param menu 菜单信息
     * @return 路由名称
     */
    public String getRouteName ( SysMenu menu ) {
        String routerName = StringUtils.capitalize ( menu.getPath () );
        // 非外链并且是一级目录（类型为目录）
        if ( isMeunFrame ( menu ) ) {
            routerName = StringUtils.EMPTY;
        }
        return routerName;
    }

    /**
     * 获取路由地址
     *
     * @param menu 菜单信息
     * @return 路由地址
     */
    public String getRouterPath ( SysMenu menu ) {
        String routerPath = menu.getPath ();
        // 非外链并且是一级目录（类型为目录）
        if ( "0".equals ( menu.getParentId () ) && UserConstants.TYPE_DIR.equals ( menu.getMenuType () )
                && UserConstants.NO_FRAME.equals ( menu.getIsFrame () ) ) {
            routerPath = "/" + menu.getPath ();
        }
        // 非外链并且是一级目录（类型为菜单）
        else if ( isMeunFrame ( menu ) ) {
            routerPath = "/";
        }
        return routerPath;
    }

    /**
     * 获取组件信息
     *
     * @param menu 菜单信息
     * @return 组件信息
     */
    public String getComponent ( SysMenu menu ) {
        String component = UserConstants.LAYOUT;
        if ( StringUtils.isNotEmpty ( menu.getComponent () ) && ! isMeunFrame ( menu ) ) {
            component = menu.getComponent ();
        }
        return component;
    }

    /**
     * 是否为菜单内部跳转
     *
     * @param menu 菜单信息
     * @return 结果
     */
    public boolean isMeunFrame ( SysMenu menu ) {
        return menu.getParentId ().equals ( "0" ) && UserConstants.TYPE_MENU.equals ( menu.getMenuType () )
                && menu.getIsFrame ().equals ( UserConstants.NO_FRAME );
    }

}
